import socket
import time
from datetime import datetime, date, timedelta
from PIL import Image, ImageDraw, ImageFont
import Adafruit_SSD1306
import os
import threading
import json
import logging
time.sleep(10)
# 配置
OLED_WIDTH = 128
OLED_HEIGHT = 64
SCHEDULE_DIR = "./schedules"
TODAY_FILE = f"schedule_{date.today().isoformat()}.json"
FONT_PATH = "NotoSansCJKsc-Regular.otf"
os.makedirs(SCHEDULE_DIR, exist_ok=True)

# 初始化OLED
disp = Adafruit_SSD1306.SSD1306_128_64(rst=None)
disp.begin()
disp.clear()
disp.display()

# 字体加载
try:
    fonts = {
        'time': ImageFont.truetype(FONT_PATH, 14),
        'task': ImageFont.truetype(FONT_PATH, 12),
        'countdown': ImageFont.truetype(FONT_PATH, 10)
    }
except:
    default = ImageFont.load_default()
    fonts = {'time': default, 'task': default, 'countdown': default}

# 全局变量
current_schedule = []
schedule_updated = False
stop_listener = False
schedule_lock = threading.Lock()

def debug_log(message):
    """调试日志"""
    with open("./schedule_debug.log", "a") as f:
        f.write(f"{datetime.now()}: {message}\n")

def clear_display():
    image = Image.new('1', (OLED_WIDTH, OLED_HEIGHT))
    draw = ImageDraw.Draw(image)
    disp.image(image)
    disp.display()

def display_task(task_info):
    """显示任务和倒计时"""
    image = Image.new('1', (OLED_WIDTH, OLED_HEIGHT))
    draw = ImageDraw.Draw(image)

    # 当前时间
    now = datetime.now().strftime("%H:%M")
    time_width = draw.textlength(now, font=fonts['time'])
    draw.text(((OLED_WIDTH - time_width)//2, 2), now, font=fonts['time'], fill=255)

    # 任务内容
    task = task_info['task']
    is_chinese = any(ord(c) > 127 for c in task)
    chunk_size = 8 if is_chinese else 16
    lines = [task[i:i+chunk_size] for i in range(0, len(task), chunk_size)]

    for i, line in enumerate(lines[:2]):
        y = 20 + i*14
        draw.text((5, y), line, font=fonts['task'], fill=255)

    # 倒计时
    if task_info['mins_left'] > 0:
        countdown = f"{task_info['mins_left']}分{'剩余' if task_info['is_current'] else '后开始'}"
        if task_info['is_review']:
            countdown = "★复习★ " + countdown
        draw.text((5, OLED_HEIGHT-12), countdown, font=fonts['countdown'], fill=255)

    disp.image(image)
    disp.display()

def load_schedule():
    """从文件加载日程"""
    try:
        filepath = os.path.join(SCHEDULE_DIR, TODAY_FILE)
        debug_log(f"尝试加载文件: {filepath}")

        if os.path.exists(filepath):
            with open(filepath, 'r') as f:
                data = json.load(f)
                debug_log(f"文件内容: {json.dumps(data, indent=2)}")

                if data.get('date') == date.today().isoformat():
                    schedule = data.get('schedule', [])
                    debug_log(f"解析到的日程: {schedule}")
                    return schedule
    except Exception as e:
        debug_log(f"加载日程出错: {str(e)}")
    return []

def save_schedule(schedule):
    """保存日程到文件"""
    try:
        with open(os.path.join(SCHEDULE_DIR, TODAY_FILE), 'w') as f:
            json.dump({
                'date': date.today().isoformat(),
                'schedule': schedule,
                'received_at': datetime.now().isoformat()
            }, f, indent=2)
    except Exception as e:
        debug_log(f"保存日程出错: {str(e)}")

def parse_time(time_str):
    """更健壮的时间解析"""
    try:
        return datetime.strptime(time_str.strip(), "%H:%M").time()
    except ValueError:
        # 尝试处理可能的额外空格或格式
        time_str = time_str.replace('：', ':').replace(' ', '')
        if len(time_str) == 4:  # 处理"900-1200"格式
            time_str = f"{time_str[:2]}:{time_str[2:]}"
        return datetime.strptime(time_str, "%H:%M").time()

def get_current_task():
    """获取当前任务信息"""
    now = datetime.now()
    current_time = now.time()
    debug_log(f"\n当前系统时间: {current_time}")

    for task in current_schedule:
        try:
            time_range = task.get('time', '')
            debug_log(f"处理任务: {task.get('task')} 时间: {time_range}")

            if '-' not in time_range:
                continue

            start_str, end_str = time_range.split('-', 1)
            start = parse_time(start_str)
            end = parse_time(end_str)

            debug_log(f"解析后时间: {start} - {end}")

            if start <= current_time <= end:
                mins_left = int((datetime.combine(now.date(), end) - now).total_seconds() // 60)
                debug_log(f"找到当前任务: {task['task']} 剩余{mins_left}分钟")
                return {
                    'task': task['task'],
                    'mins_left': max(0, mins_left),
                    'is_current': True,
                    'is_review': task.get('type') == 'review'
                }
        except Exception as e:
            debug_log(f"解析任务时间出错: {str(e)}")
            continue

    # 查找下一个任务
    upcoming = []
    for task in current_schedule:
        try:
            time_range = task.get('time', '')
            if '-' not in time_range:
                continue

            start_str = time_range.split('-')[0]
            start = parse_time(start_str)

            if start > current_time:
                start_dt = datetime.combine(now.date(), start)
                mins_left = int((start_dt - now).total_seconds() // 60)
                upcoming.append({
                    'task': task['task'],
                    'mins_left': mins_left,
                    'is_current': False,
                    'is_review': task.get('type') == 'review'
                })
        except Exception as e:
            debug_log(f"解析即将任务出错: {str(e)}")
            continue

    if upcoming:
        next_task = min(upcoming, key=lambda x: x['mins_left'])
        debug_log(f"找到下一个任务: {next_task['task']} ({next_task['mins_left']}分钟后)")
        return next_task

    debug_log("未找到有效任务")
    return {
        'task': '今日无更多任务',
        'mins_left': 0,
        'is_current': False,
        'is_review': False
    }

def listener_thread():
    """网络监听线程"""
    global current_schedule, schedule_updated

    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind(('0.0.0.0', 5000))
        s.listen(1)
        debug_log("监听服务已启动")

        while not stop_listener:
            try:
                conn, addr = s.accept()
                with conn:
                    conn.settimeout(10)  # 设置超时
                    data = b''
                    
                    # 持续接收直到遇到结束标记
                    while True:
                        chunk = conn.recv(4096)
                        if not chunk:
                            break
                        data += chunk
                        if b'\nEND_OF_JSON\n' in data:
                            break
                    
                    # 提取并清理JSON数据
                    json_str = data.decode('utf-8').split('\nEND_OF_JSON\n')[0]
                    debug_log(f"接收到的JSON数据: {json_str[:200]}...")  # 只打印前200字符
                    
                    if json_str:
                        with schedule_lock:
                            try:
                                current_schedule = json.loads(json_str)
                                debug_log(f"成功解析日程: {len(current_schedule)}条")
                                save_schedule(current_schedule)
                                schedule_updated = True
                            except json.JSONDecodeError as e:
                                debug_log(f"JSON解析失败: {str(e)}")
                                debug_log(f"原始数据: {json_str}")
            except Exception as e:
                if not stop_listener:
                    debug_log(f"监听错误: {str(e)}")
                    time.sleep(1)

def main():
    global current_schedule, stop_listener, schedule_updated
    
    # 检查数据目录是否存在
    if not os.path.exists(SCHEDULE_DIR):
        os.makedirs(SCHEDULE_DIR)
        debug_log(f"创建目录: {SCHEDULE_DIR}")
    
    # 初始化加载
    try:
        current_schedule = load_schedule()
        debug_log(f"初始加载 {len(current_schedule)} 条日程")
    except Exception as e:
        debug_log(f"初始加载失败: {str(e)}")
        current_schedule = []
    
    schedule_updated = True
    
    # 启动监听线程
    thread = threading.Thread(target=listener_thread)
    thread.daemon = True
    thread.start()

    try:
        last_minute = -1
        while not stop_listener:
            now = datetime.now()

            # 每分钟或收到更新时刷新
            if schedule_updated or now.minute != last_minute:
                current_task = get_current_task()
                debug_log(f"显示任务: {current_task}")
                display_task(current_task)
                schedule_updated = False
                last_minute = now.minute

            time.sleep(0.5)

    except KeyboardInterrupt:
        pass
    finally:
        stop_listener = True
        thread.join()
        clear_display()
        debug_log("程序正常退出")

if __name__ == "__main__":
    main()